//
// Created by Administrator on 2021/3/1.
//

#include "calculator.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

static void ClearBuffer(CalcContext *context){
  context->input_buffer[0] = 0;
  context->input_buffer_position = 0;
}

static void ClearAll(CalcContext *context){
  ClearBuffer(context);
  context->result = 0;
  memset(&context->previous_operation, 0, sizeof(Operation));
  memset(&context->current_operation, 0, sizeof(Operation));
}

//输入一个字符以后 就会马上调用一次FormatInput
static void FormatInput(CalcContext *context){
  //什么都还没有输入
  if (context->input_buffer_position == 0) {
    context->input_buffer[0] = '0';
    context->input_buffer[1] = 0; //用于标识字符串结尾的
    context->input_buffer_position = 1;

  //仅输入了一个字符
  } else if (context->input_buffer_position == 1) {
    //一来就输入了一个 `.`
    if (context->input_buffer_position == '.'){
      context->input_buffer[0] = '0';
      context->input_buffer[1] = '.';
      context->input_buffer[2] = 0; //用于标识字符串结尾的
      context->input_buffer_position = 2;
    }

  //输入的字符大于等于2个
  } else if(context->input_buffer_position > 1){
    char *p = context->input_buffer;

    //输入了2个字符 如果输入的第一个字符原本为0, 第二个字符不为. (即想要输入的不是小数)
    if(p[0] == '0' && p[1] != '.') {
      p[0] = p[1];
      p[1] = 0;
      context->input_buffer_position = 1;

    // 输入的最新的字符为 `.` (即准备输入的是一个小数)
    // 此时如果前面已经有 `.`, 那么此次输入无效
    } else if (p[context->input_buffer_position - 1] == '.') {
      for (int i = 0; i < context->input_buffer_position - 1; ++i) {
        if (p[i] == '.') {
          context->input_buffer_position--;
          p[context->input_buffer_position] = 0;
          break;
        }
      }
    }
  }
}

static void DisplayInput(CalcContext *context){
  FormatInput(context);
  context->display_text(context->input_buffer);
}

static void FormatOutput(CalcContext *context){
  if(context->result == -0.0){
    context->result = 0.0;
  }

  sprintf(context->input_buffer, "%.6g", context->result); //占时借用一下input_buffer的位置
  //%.6g
  //6->有效位数为6位
  //g 根据数值类型不同自动选择%f或%e(科学计数法)
}

static void DisplayOutput(CalcContext *context){
  FormatOutput(context);
  context->display_text(context->input_buffer);
  ClearBuffer(context);
}

/*
operand
US: ['ɒpərænd]
UK: ['ɒpərænd]
n.	操作数；运算对象
Web	运算元；显示操作对象；运算数
*/
static void ApplyInput(CalcContext *context, double *operand){
  if (context->input_buffer_position > 0) {
    //atox 的 a代表acsii
    //x是值要转换成的目标类型
    *operand = atof(context->input_buffer); //把字符串转成double
    ClearBuffer(context); //只会清除 input_buffer、input_buffer_position
  }else {
    *operand = context->result;
  }
}

static void ApplyInputToLeft(CalcContext *context){
  ApplyInput(context,&context->current_operation.left);
}

static void ApplyInputToRight(CalcContext *context){
  ApplyInput(context,&context->current_operation.right);
}

static void ApplyCurrentOperation(CalcContext *context){
  context->result = OperationApply(&context->current_operation);
  memcpy(&context->previous_operation, &context->current_operation, sizeof(Operation));
  memset(&context->current_operation, 0, sizeof(Operation));
}

static void ApplyPreviousOperation(CalcContext *context){
  context->result = OperationApply(&context->previous_operation);
}

int HandleInput(CalcContext *context, char input_value){
//  if (context->display_text) {
//    //不论display_text是什么 它接受的都是一个字符串
//    //如果我们这里强制把字符当做字符串传入 &input_value
//    //那么可能会有bug 它根部不知道这个假字符串什么时候结束
//    //context->display_text(&input_value);
//
//    char output_value[2] = {input_value};
//    context->display_text(output_value);
//  }

  switch (input_value) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case '.':{
      if (context->input_buffer_position < MAX_CHAR) {
        context->input_buffer[context->input_buffer_position++] = input_value;
        context->input_buffer[context->input_buffer_position] = '\0'; //标识字符串结尾需要
      }
      DisplayInput(context);
      break;
    }
    case '+':{
      context->current_operation.operator = Plus;
      ApplyInputToLeft(context);
      break;
    }
    case '-':{
      context->current_operation.operator = Minus;
      ApplyInputToLeft(context);
      break;
    }
    case '*':{
      context->current_operation.operator = Multiply;
      ApplyInputToLeft(context);
      break;
    }
    case '/':{
      context->current_operation.operator = Divide;
      ApplyInputToLeft(context);
      break;
    }
    case '%':{
      ApplyInputToLeft(context);
      context->current_operation.operator = Multiply;
      context->current_operation.right = 0.01;
      ApplyCurrentOperation(context);
      DisplayOutput(context);
      break;
    }
    case '=':{
      if (context->current_operation.operator){
        ApplyInputToRight(context);
        ApplyCurrentOperation(context);
        DisplayOutput(context);
      } else if (context->previous_operation.operator) {
        context->previous_operation.left = context->result;
        ApplyPreviousOperation(context);
        DisplayOutput(context);
      }
      break;
    }
    case 'S':
      ApplyInputToLeft(context);
      context->current_operation.operator = Multiply;
      context->current_operation.right = -1;
      ApplyCurrentOperation(context);
      DisplayOutput(context);
      break;
    case 'C':
      ClearAll(context);
      DisplayInput(context);
      break;
  }

  return 1; //输入合法返回1
}

CalcContext *CreateCalcContext(){
  CalcContext *calc_context = malloc(sizeof(CalcContext));
  ClearAll(calc_context);
  calc_context->display_text = NULL;
  return calc_context;
}

void DestroyCalcContext(CalcContext **p_context){
  free(*p_context); //free掉malloc申请的
  *p_context = NULL; //防止野指针
};
